<template>
  <scroll-view
    class="su-list"
    :scrollX="scrollX"
    :scrollY="scrollY"
    :scrollTop="scrollTop"
    :enableFlex="enableFlex"
    :scrollAnchoring="scrollAnchoring"
    :refresherEnabled="refresherEnabled"
    @scroll="onScroll"
    @scrolltoupper="onScrollToUpper"
    @scrolltolower="onScrollToLower"
  >
    <view class="su-list--scroll">
      <view class="su-list__refreshing" v-if="refreshing">
        <IconLoading color="#999" />
        <text>{{ refreshTxt }}</text>
      </view>
      <view class="su-list__content">
        <slot></slot>
      </view>
      <view class="su-list__loading" v-if="loading">
        <IconLoading color="#999" />
        <text>{{ loadTxt }}</text>
      </view>
      <nut-divider v-if="!hasMore"> {{ loadMoreTxt }} </nut-divider>
    </view>
  </scroll-view>
</template>

<script setup>
import { Loading as IconLoading } from '@nutui/icons-vue';
import { useVModel } from '@vueuse/core';
import { isFunction, get } from 'lodash-es';
defineOptions({
  name: 'SuList'
});
const props = defineProps({
  modelValue: {
    type: Array,
    default: () => []
  },
  scrollX: {
    type: Boolean,
    default: false
  },
  scrollY: {
    type: Boolean,
    default: true
  },
  enableFlex: {
    type: Boolean,
    default: false
  },
  scrollAnchoring: {
    type: Boolean,
    default: true
  },
  refresherEnabled: {
    type: Boolean,
    default: false
  },
  onScroll: {
    type: Function,
    default: undefined
  },
  onLoad: {
    type: Function,
    default: undefined
  },
  listBefore: {
    type: Function,
    default: undefined
  },
  listAfter: {
    type: Function,
    default: undefined
  },
  dataPath: {
    type: String,
    default: 'data.records'
  },
  totalPath: {
    type: String,
    default: 'data.total'
  },
  pageKey: {
    type: String,
    default: 'current'
  },
  pageSizeKey: {
    type: String,
    default: 'size'
  },
  loadMoreTxt: {
    type: String,
    default: '哎呀，这里是底部了啦'
  },
  loadTxt: {
    type: String,
    default: '加载中...'
  },
  refreshTxt: {
    type: String,
    default: '下拉刷新...'
  }
});
const emit = defineEmits(['update:modelValue']);
const { onLoad, listBefore, listAfter, params, dataPath, totalPath, pageKey, pageSizeKey } = props;
const refreshing = ref(false);
const loading = ref(false);
const scrollTop = ref(0);
const data = useVModel(props, 'modelValue', emit);
const hasMore = ref(true);
const page = ref({
  current: 1,
  size: 20,
  total: 0
});

async function onScrollToUpper(e) {
  scrollTop.value = e.detail.scrollTop;
  if (scrollTop.value === 0 && !refreshing.value) {
    try {
      refreshing.value = true;
      await loadMore();
    } finally {
      refreshing.value = false;
    }
  }
}
// 到达底部时触发
const onScrollToLower = async () => {
  if (!loading.value && hasMore.value) {
    try {
      loading.value = true;
      await loadMore();
    } finally {
      loading.value = false;
    }
  }
};
const loadMore = async () => {
  const query = {
    ...unref(params)
  };
  if (!hasMore.value) {
    return;
  }
  if (!isFunction(onLoad)) {
    console.error('onLoad must be a function');
    return;
  }
  if (isFunction(listBefore)) {
    let result = listBefore(query);
    if (result === false) {
      return;
    }
  }
  const { current, size } = page.value;
  const raw = await onLoad({
    [pageKey]: current,
    [pageSizeKey]: size,
    ...query
  });
  let payload = raw.data;
  let records = get(payload, dataPath) || [];
  let total = get(payload, totalPath) || [];
  if (isFunction(listAfter)) {
    records = listAfter(records);
  }
  data.value.push(...records);
  page.value.current++;
  page.value.total = total;
  if (data.value.length >= total) {
    hasMore.value = false;
  }
};
const refresh = async () => {
  page.value.current = 1;
  page.value.total = 0;
  data.value = [];
  hasMore.value = true;
  await loadMore();
};

defineExpose({
  data,
  hasMore,
  loadMore,
  refresh
});
onMounted(() => {
  loadMore();
});
</script>

<style lang="scss">
.su-list {
  @include wh(100%, 100%);
  @include flex(column nowrap);
  &--scroll {
    @include wh(100%, 100%);
    overflow-y: auto;
    flex: 1;
  }
  &__content {
    @include wh(100%, 100%);
  }
  &-loading,
  &-refresh {
    @include wh(100%, 50px, 50px);
    @include flex(row nowrap, center, center, 10px);
    @include fs(12px, #999);
  }
}
</style>
